package dea;

import initializer.Start;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JOptionPane;

import pdm.Pdm;

import lpsolve.*;

public class Dea {

	public List<Dmu> dmulist;

	public Dea(String fileName) throws Exception {
		try {
			this.dmulist = this.LoadFile(fileName);
		} catch(Exception e){
			throw(e);
		}
	}

	public Dea(List<Dmu> dmulist) {
		this.dmulist = dmulist;
	}

	public DeaSolution CalcDEA(int currentDmu) {
		try {

			LpSolve lp = ConstructLPModel(currentDmu);

			lp.setVerbose(LpSolve.IMPORTANT);
			//lp.writeLp("DEA_model_" + currentDmu + ".lp");
			lp.solve();

			double[] variables = new double[lp.getNcolumns()];
			lp.getVariables(variables);

			for(int i = 0; i< variables.length; i++)
			{
		    	variables[i] = Pdm.RoundUp(variables[i]);
		    	
			}

			return new DeaSolution(lp.getVarPrimalresult(0), variables);

		} catch (NumberFormatException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (LpSolveException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	@SuppressWarnings("deprecation")
	private List<Dmu> LoadFile(String filename) throws NumberFormatException,
			IOException {

		Pdm.print("URL: " + filename);
		//System.out.println("PATH : " + System.getProperty("java.library.path"));
		URL Datastream = new File(filename).toURL();
		BufferedReader t = new BufferedReader(new InputStreamReader(Datastream.openStream()));
		String currLine;
		List<Dmu> temp = new ArrayList<Dmu>();
		List<String> inputs = new ArrayList<String>();
		List<String> outputs = new ArrayList<String>();

		// Header ROW
		currLine = t.readLine();
		// Debug.WriteLine(currLine);
		String[] inout = currLine.split(";&;");
		// Debug.WriteLine("Inputs: " + inout[0] + "  --  outputs: " +
		// inout[1]);
		for (String i : inout[0].split(";")) {
			inputs.add(i);
		}
		for (String o : inout[1].split(";")) {
			outputs.add(o);
		}

		int p = 0;
		// All value Rows
		while ((currLine = t.readLine()) != null) {
			// Debug.WriteLine(currLine);
			inout = currLine.split(";&;");
			Dmu curr = new Dmu();
			curr.ID = ++p;

			String[] ins = inout[0].split(";");

			for (int r = 0; r < inputs.size(); r++) {
				/*
				 * String[] inpVal = ins[r].split("/"); Double currVal =
				 * Double.parseDouble(inpVal[0]) /
				 * Double.parseDouble(inpVal[1]); curr.Inputs.add(new
				 * InputValue(inputs.get(r), currVal));
				 */
				curr.Inputs.add(new InputValue(inputs.get(r), Double
						.parseDouble(ins[r])));
			}

			String[] outs = inout[1].split(";");
			double initWeight = -1;
			for (int r = 0; r < outputs.size(); r++) {
				/*String[] outVal = new String[2];
				outVal = outs[r].split("/");
				Double currVal = Double.parseDouble(outVal[0])
						/ Double.parseDouble(outVal[1]);
				OutputValue z;
				if (r == 0) {
					initWeight = Double.parseDouble(outVal[1]);
					z = new OutputValue(outputs.get(r), currVal, 1.0);
				} else {
					z = new OutputValue(outputs.get(r), currVal, Double
							.parseDouble(outVal[1])
							/ initWeight);
					// print(Double.parseDouble(outVal[1])/initWeight);
				}
				curr.Outputs.add(z);*/
				if(r == 0){
					curr.Outputs.add(new OutputValue(outputs.get(r), Double.parseDouble(outs[r]), 1.0));
					Pdm.print(outputs.get(r) + " - " + Double.parseDouble(outs[r]) + " - " + 1.0);
				}
				else{
					curr.Outputs.add(new OutputValue(outputs.get(r), Double.parseDouble(outs[r]), Double.parseDouble(outs[r])/Double.parseDouble(outs[0])));
					Pdm.print(outputs.get(r) + " - " + Double.parseDouble(outs[r]) + " - " + Double.parseDouble(outs[r])/Double.parseDouble(outs[0]));
				}
				
			}
			temp.add(curr);
		}
		return temp;
	}

	private LpSolve ConstructLPModel(int currDmu) throws LpSolveException {
		LpSolve lp;
		int j = 0;
		int Ncol = this.dmulist.get(0).Outputs.size()
				+ this.dmulist.get(0).Inputs.size();

		int[] colNo = new int[Ncol];
		double[] row = new double[Ncol];

		lp = LpSolve.makeLp(0, Ncol);
		if (lp.getLp() == 0) {
			print("Could not generate new LP model");
			return null;
		}
		for (int i = 1; i <= Ncol; i++)
			lp.setColName(i, "u" + i);

		; /* makes building the model faster if it is done rows by row */

		// now add all constraints and the objective function

		// add obj function
		j = 0;
		for (int x = 1; x <= dmulist.get(currDmu).Outputs.size(); x++) {
			colNo[j] = x;
			row[j++] = dmulist.get(currDmu).Outputs.get(x - 1).OutputVal;
		}
		lp.setObjFnex(j, row, colNo);

		lp.setAddRowmode(true);

		// add denominator equality constraint
		j = 0;
		for (int x = dmulist.get(currDmu).Outputs.size() + 1; x <= dmulist
				.get(currDmu).Outputs.size()
				+ dmulist.get(currDmu).Inputs.size(); x++) {
			colNo[j] = x;
			row[j++] = dmulist.get(currDmu).Inputs.get(x
					- dmulist.get(currDmu).Outputs.size() - 1).InputVal;
		}
		lp.addConstraintex(j, row, colNo, LpSolve.EQ, 1);

		// add LE constraint
		for (int dmu = 0; dmu < dmulist.size(); dmu++) {

			j = 0;
			for (int x = 1; x <= dmulist.get(dmu).Outputs.size(); x++) {
				colNo[j] = x;
				row[j++] = dmulist.get(dmu).Outputs.get(x - 1).OutputVal * -1;
				// lp.setLowbo(x, 0.02);
			}
			for (int x = 1; x <= dmulist.get(dmu).Inputs.size(); x++) {
				colNo[j] = x + dmulist.get(dmu).Outputs.size();
				row[j++] = dmulist.get(dmu).Inputs.get(x - 1).InputVal;
			}

			lp.addConstraintex(j, row, colNo, LpSolve.GE, 0);
		}
		// limit variation of variable values to 1/10
		for (int x = 1; x <= dmulist.get(currDmu).Outputs.size() - 1; x++) {
			for (int z = 1; z <= dmulist.get(currDmu).Outputs.size(); z++) {
				if(z != x){
					row = new double[Ncol];
					row[x] = -0.1;
					row[z] = 1;
					lp.addConstraint(row, LpSolve.GE, 0);
				}
			}
		}

		lp.setAddRowmode(false);
		/* set the object direction to maximize */
		lp.setMaxim();

		return lp;

	}

	private static void print(Double text) {
		System.out.println(text);
	}

	private static void print(String text) {
		System.out.println(text);
	}
}
